package com.pair.micro.fee.modules.charge.service.impl;

import ch.qos.logback.core.net.SyslogOutputStream;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.pair.micro.common.constant.Constant;
import com.pair.micro.common.constant.MicroBusinessError;
import com.pair.micro.common.exception.MicroBusinessException;
import com.pair.micro.common.mybatis.service.impl.BaseServiceImpl;
import com.pair.micro.common.utils.DefinitionCode;
import com.pair.micro.common.utils.PageResult;
import com.pair.micro.fee.modules.charge.convert.ChargeProjectConvert;
import com.pair.micro.fee.modules.charge.convert.ChargeProjectConvert;
import com.pair.micro.fee.modules.charge.dao.ChargeProjectDao;
import com.pair.micro.fee.modules.charge.dao.ChargeProjectDao;
import com.pair.micro.fee.modules.charge.dao.ChargeReceiveDao;
import com.pair.micro.fee.modules.charge.dao.RoomOwnerDao;
import com.pair.micro.fee.modules.charge.entity.*;
import com.pair.micro.fee.modules.charge.entity.ChargeProjectEntity;
import com.pair.micro.fee.modules.charge.query.ChargeProjectQuery;
import com.pair.micro.fee.modules.charge.query.ChargeProjectQuery;
import com.pair.micro.fee.modules.charge.service.ChargeProjectService;
import com.pair.micro.fee.modules.charge.service.ChargeProjectService;
import com.pair.micro.fee.modules.charge.service.ChargeReceiveService;
import com.pair.micro.fee.modules.charge.service.RoomOwnerService;
import com.pair.micro.fee.modules.charge.vo.ChargeProjectVO;
import com.pair.micro.fee.modules.charge.vo.ChargeReceiveVO;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
public class ChargeProjectServiceImpl extends BaseServiceImpl<ChargeProjectDao, ChargeProjectEntity> implements ChargeProjectService {
    @Resource
    private DefinitionCode definitionCode;

    private final RoomOwnerDao roomOwnerDao;

    private final ChargeReceiveService chargeReceiveService;


    private final ChargeProjectDao chargeProjectDao;

    @Override
    public PageResult<ChargeProjectVO> page(ChargeProjectQuery query) {
        Map<String, Object> params = getParams(query);
        // 分页查询
        IPage<ChargeProjectEntity> page = getPage(query);
        params.put(Constant.PAGE, page);
        List<ChargeProjectEntity> list = baseMapper.getList(params);

        return new PageResult<>(ChargeProjectConvert.INSTANCE.convertList(list), page.getTotal());
    }

    private Map<String, Object> getParams(ChargeProjectQuery query) {
        Map<String, Object> params = new HashMap<>();
        params.put("name", query.getName());
        params.put("chargeType", query.getChargeType());
        params.put("chargeState", query.getChargeState());
        return params;
    }

    @Override
    public  List<RoomOwnerEntity> checkParams(ChargeProjectVO vo) {
        Map<String, Object> params = new HashMap<>();
        if (Constant.GARDEN_RANGE.equals(vo.getChargeRange())){ //收费范围 小区 楼栋 单元 房屋
            params.put("gardenId",vo.getGardenId());
        } else if (Constant.HOUSE_RANGE.equals(vo.getChargeRange())){
            params.put("gardenId",vo.getGardenId());
            params.put("houseId",vo.getHouseId());
        } else if (Constant.UNIT_RANGE.equals(vo.getChargeRange())){
            params.put("gardenId",vo.getGardenId());
            params.put("houseId",vo.getHouseId());
            params.put("unitId",vo.getUnitId());
        } else if (Constant.ROOM_RANGE.equals(vo.getChargeRange())){
            params.put("gardenId",vo.getGardenId());
            params.put("houseId",vo.getHouseId());
            params.put("unitId",vo.getUnitId());
            params.put("roomId",vo.getRoomId());
        }
        List<RoomOwnerEntity> list = roomOwnerDao.getList(params);
        if(list.size()==0) throw  new MicroBusinessException(MicroBusinessError.BIS_50001);
        list.forEach(item->{
            String describe;
            if(Constant.CHARGE_TYPE_PROPERTY.equals(vo.getConfigVO().getChargeType())){ //收费类型为物业费
                if(item.getArea()==null||item.getArea()==0.0f){
                    describe = item.getGardenName() + "-" + item.getHouseName()+"号楼"+"-"+item.getUnitName() + "单元" + "-" + item.getRoomName() +":"+ "无面积";
                    throw new MicroBusinessException(MicroBusinessError.BIS_20010,describe);
                }
                LambdaQueryWrapper<ChargeProjectEntity> wrapper = Wrappers.<ChargeProjectEntity>lambdaQuery().eq(ChargeProjectEntity::getConfigId, vo.getConfigVO().getId()).eq(ChargeProjectEntity::getRoomId, item.getRoomId()).eq(ChargeProjectEntity::getChargeState, Constant.CHARGING);
                List<ChargeProjectEntity> chargeProjectEntities = baseMapper.selectList(wrapper);
                if(chargeProjectEntities.size()>0){ //收费类型为物业费 并且存在收费中状态
                    describe = item.getGardenName() + "-" + item.getHouseName()+"号楼"+"-"+item.getUnitName() + "单元" + "-" + item.getRoomName() +":"+ "物业费-收费中";
                    throw new MicroBusinessException(MicroBusinessError.BIS_20010,describe);
                }
            }else if (Constant.CHARGE_TYPE_CAR.equals(vo.getConfigVO().getChargeType())||Constant.CHARGE_TYPE_CASUAL_CAR.equals(vo.getConfigVO().getChargeType())) { //如果是车位费或者临时车位费
                LambdaQueryWrapper<ChargeProjectEntity> wrapper = Wrappers.<ChargeProjectEntity>lambdaQuery().eq(ChargeProjectEntity::getCarPlaceId, vo.getCarPlaceId()).eq(ChargeProjectEntity::getChargeState, Constant.CHARGING);
                List<ChargeProjectEntity> chargeProjectEntities = baseMapper.selectList(wrapper);
                if(chargeProjectEntities.size()>0){ //收费类型为车位费 并且存在收费中状态
                    describe = item.getGardenName() + "-" + item.getHouseName()+"号楼"+"-"+item.getUnitName() + "单元" + "-" + item.getRoomName() + ":"+"车位费-收费中";
                    throw new MicroBusinessException(MicroBusinessError.BIS_20010,describe);
                }
            }
        });
        return list;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(List<RoomOwnerEntity> list, ChargeProjectVO vo) {
        List<ChargeProjectEntity> entities = new  ArrayList<>();
        list.forEach(item->{
            ChargeProjectEntity entity = new ChargeProjectEntity();
            BigDecimal unitPrice = vo.getConfigVO().getUnitPrice();
            BigDecimal area = new BigDecimal(String.valueOf(item.getArea()));
            BigDecimal additionalFee = vo.getConfigVO().getAdditionalFee();
            String chargeFormula = vo.getConfigVO().getChargeFormula();
            String chargeMark = vo.getConfigVO().getChargeMark();
            String id = String.valueOf(definitionCode.nextId(DefinitionCode.CODE_PREFIX_CHARGE_PROJECT));
            String configId=vo.getConfigVO().getId();
            Integer carPlaceId = vo.getCarPlaceId();
            Date beginTime = vo.getStartTime();
            Date startTime = vo.getStartTime();
            Date endTime = vo.getConfigVO().getEndTime();
            BigDecimal payFeeAmount;
            if(chargeFormula.equals(Constant.UNIT_PRICE_AREA)){ //如果公式为单价乘以面积加上附加费用 计算出月费用
                payFeeAmount = unitPrice.multiply(area).add(additionalFee).setScale(2, BigDecimal.ROUND_HALF_EVEN);
            }else if(chargeFormula.equals(Constant.FIXED_COSTS)){ //固定费用
                payFeeAmount = additionalFee.setScale(2, BigDecimal.ROUND_HALF_EVEN);
            }else{
                throw new MicroBusinessException(MicroBusinessError.BIS_20010,"暂时不支持该类公式");
            }
            if(chargeMark.equals(Constant.CYCLE_FEE)){ //如果是周期性费用

                //取出相差多少个月
                LocalDateTime startDay = LocalDateTime.ofInstant(startTime.toInstant(), ZoneId.systemDefault());
                LocalDateTime endTDay = LocalDateTime.ofInstant(endTime.toInstant(), ZoneId.systemDefault());
                int betweenMonth = (int)ChronoUnit.MONTHS.between(startDay, endTDay);

                //收费设置结束时间为月底
                LocalDateTime last = LocalDateTime.from(startDay.with(TemporalAdjusters.lastDayOfMonth()));
                int lastDay = last.getDayOfMonth();
                int currentDay = startDay.getDayOfMonth();
                int spaceDay= lastDay-currentDay; //月最后一天减去起始时间天数
                BigDecimal revAmountBim;
                if(currentDay>1){
                    BigDecimal lastDayBim = new BigDecimal(lastDay);
                    BigDecimal days = new BigDecimal(spaceDay + 1); //算上起始日期当天 所以加上1
                    BigDecimal betweenMonths = new BigDecimal(betweenMonth);
                    revAmountBim = payFeeAmount.divide(lastDayBim, 2, BigDecimal.ROUND_HALF_UP).multiply(days).add(payFeeAmount.multiply(betweenMonths));
                    entity.setRevAmount(revAmountBim);
                }else{
                    BigDecimal results = new BigDecimal(betweenMonth + 1); //收费设置截止日期 为当月最后一天  所以月份加一
                    revAmountBim = payFeeAmount.multiply(results);
                    entity.setRevAmount(revAmountBim);
                }
            }else{
                entity.setRevAmount(payFeeAmount);
            }
            if (Constant.CHARGE_TYPE_CAR.equals(vo.getConfigVO().getChargeType())||Constant.CHARGE_TYPE_CASUAL_CAR.equals(vo.getConfigVO().getChargeType())) { //如果是车位费或者临时车位费
                entity.setProjectType(Constant.PROJECT_TYPE_CAR_PLACE_FEE);
                entity.setCarPlaceId(carPlaceId);
            }else {
                entity.setProjectType(Constant.PROJECT_TYPE_HOUSE_FEE);
            }
            entity.setId(id);
            entity.setConfigId(configId);
            entity.setGardenId(item.getGardenId());
            entity.setHouseId(item.getHouseId());
            entity.setUnitId(item.getUnitId());
            entity.setRoomId(item.getRoomId());
            entity.setBeginTime(beginTime);
            entity.setStartTime(startTime);
            entity.setEndTime(endTime);
            entity.setChargeState(Constant.CHARGING);
            entity.setOperatorId(vo.getOperator());
            entities.add(entity);

        });
        saveBatch(entities);

    }
    @Override
    public void charge(ChargeProjectVO vo) {
        ChargeDetailEntity chargeDetail = new ChargeDetailEntity();
        String detailId = String.valueOf(definitionCode.nextId(DefinitionCode.CODE_PREFIX_CHARGE_DETAIL));
        String projectId = vo.getId();
        String chargeFormula = vo.getConfigVO().getChargeFormula();
        BigDecimal unitPrice = vo.getConfigVO().getUnitPrice();
        BigDecimal area = new BigDecimal(String.valueOf(vo.getArea()));
        BigDecimal additionalFee = vo.getConfigVO().getAdditionalFee();
        String chargeMark = vo.getConfigVO().getChargeMark();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM"); // 定义格式化模式为"yyyy-MM"
        Date startTime = vo.getStartTime();//收费项 开始时间
        Date endTime = vo.getConfigVO().getEndTime(); //收费设置 结束时间
        BigDecimal revAmount = vo.getRevAmount(); // 收费项应收金额
        BigDecimal payFeeAmount;
        if(chargeFormula.equals(Constant.UNIT_PRICE_AREA)){ //如果公式为单价乘以面积加上附加费用 计算出月费用
            payFeeAmount = unitPrice.multiply(area).add(additionalFee).setScale(2, BigDecimal.ROUND_HALF_EVEN);
        }else if(chargeFormula.equals(Constant.FIXED_COSTS)){ //固定费用
            payFeeAmount = additionalFee.setScale(2, BigDecimal.ROUND_HALF_EVEN);
        }else{
            throw new MicroBusinessException(MicroBusinessError.BIS_20010,"暂时不支持该类公式");
        }
        BigDecimal projectReceiveAmount = vo.getProjectReceiveAmount(); //应收费用
        BigDecimal projectPaidAmount = vo.getProjectPaidAmount();//实收费用
        //查出该收费项目下的所有账单
        LambdaQueryWrapper<ChargeReceiveEntity> receive = new LambdaQueryWrapper<>();
        receive.eq(ChargeReceiveEntity::getProjectId,projectId).eq(ChargeReceiveEntity::getState,0).eq(ChargeReceiveEntity::getStatus,0);
        List<ChargeReceiveEntity> receiveVO = chargeReceiveService.list(receive);
//      List<ChargeReceiveVO> receiveVO = vo.getReceiveVO();//账单集合
        List<ChargeReceiveDetailEntity> receiveDetailList = new ArrayList<>(); //收费详情明细集合
        Date startDate = new Date();
        if(chargeMark.equals(Constant.CYCLE_FEE)&&receiveVO.size()>0){ //周期性费用
            if(projectReceiveAmount.compareTo(projectPaidAmount)!=0){ //应收金额和实收金额不相等  手动输入金额
                BigDecimal receiveFirstAmount = receiveVO.get(0).getReceiveAmount(); //第一条账单应收费用
                //应收金额和实收金额不相等时，收费存在三种情况：1、实收费用大于账单第一个月的费用 2、实收费用等于第一个月的费用(选择多个账单，最后输入了为第一个月的费用) 3、实收费用小于第一个月的费用
                if(projectPaidAmount.compareTo(receiveFirstAmount)>-1){ //实收费用大于等于账单第一个月的费用 两种情况：1、剩余费用为整月 2、剩余费用不为整月

                    BigDecimal remainAmount = projectPaidAmount.subtract(receiveFirstAmount); //减掉第一个月 剩下的费用
                    BigDecimal remainder = remainAmount.divideAndRemainder(payFeeAmount)[1].setScale(2, BigDecimal.ROUND_HALF_UP); //数组下标0 是商值  下标为1是取余的值
                    BigDecimal m = remainAmount.divideAndRemainder(payFeeAmount)[0].setScale(2, BigDecimal.ROUND_HALF_UP); //实收费用除以月费用

                    LocalDateTime startDay = LocalDateTime.ofInstant(receiveVO.get(0).getStartDate().toInstant(), ZoneId.systemDefault()); //第一个月日期
                    LocalDateTime startFirstTime = LocalDateTime.from(startDay.with(TemporalAdjusters.firstDayOfMonth())).plusMonths(m.longValue()+1);//下次缴费的账单开始时间和收费项开始时间,因为大于第一个月所以加1
                    LocalDateTime startLastTime = LocalDateTime.from(startDay.with(TemporalAdjusters.lastDayOfMonth())).plusMonths(m.longValue()+1); //下次缴费的账单开始时间月份的最后一天


                    String period = startFirstTime.format(formatter); //下次缴费的账单开始时间的 费用区间

                    if (remainder.compareTo(BigDecimal.ZERO) == 0) { //费用为第一个月份费用或者 为整月费用
                        LocalDateTime projectEndTime = LocalDateTime.ofInstant( vo.getEndTime().toInstant(), ZoneId.systemDefault()); //收费项截止时间
                        if(startFirstTime.compareTo(projectEndTime)==1){ //说明当期收费结束了
                          vo.setChargeState(Constant.CHARGE_THIS_END);
                        }

                        startDate = toDate(startFirstTime);
                        LambdaQueryWrapper<ChargeReceiveEntity> receiveWrapper = new LambdaQueryWrapper<>();
                        //账单状态为收费中 并且账单应收区间小于下一次收费的应收区间 更新已收费状态
//                        receiveWrapper.lt(ChargeReceiveEntity::getPeriod,period).eq(ChargeReceiveEntity::getState,0).eq(ChargeReceiveEntity::getStatus,0);
//                      List<ChargeReceiveEntity> receiveEntityList = chargeReceiveService.list(receiveWrapper); //查出数据后保存，最后批量添加账单明细中
                        List<ChargeReceiveEntity> receiveEntityList = receiveVO.stream().filter(f ->  DateUtil.parse(f.getPeriod()).isBefore(DateUtil.parse(period)) ).collect(Collectors.toList());
                        receiveDetailList = receiveEntityList.stream().map(item -> {
                            String id = String.valueOf(definitionCode.nextId(DefinitionCode.CODE_PREFIX_CHARGE_RECEIVE_DETAIL));
                            ChargeReceiveDetailEntity receiveDetail = new ChargeReceiveDetailEntity();
                            ChargeReceiveEntity receiveEntity = new ChargeReceiveEntity();
                            receiveDetail.setId(id);
                            receiveDetail.setDetailId(detailId);
                            receiveDetail.setReceiveId(item.getId());
                            receiveDetail.setPeriod(item.getPeriod());
                            receiveDetail.setReceiveOldDate(item.getStartDate());
                            receiveDetail.setReceiveAmount(item.getReceiveAmount());
                            receiveDetail.setRevAmount(new BigDecimal(0));
                            receiveDetail.setPaidAmount(item.getReceiveAmount());
                            receiveDetail.setThisAmount(item.getReceiveAmount());

                            //封装 账单表
                            receiveEntity.setId(item.getId());
                            receiveEntity.setState(1);
                            receiveEntity.setRevAmount(new BigDecimal(0));
                            receiveEntity.setPaidAmount(item.getReceiveAmount());
                            chargeReceiveService.updateById(receiveEntity);
                            return receiveDetail;
                        }).collect(Collectors.toList());

                    } else { //费用不为整月
                        int lastDay = startLastTime.getDayOfMonth(); //取出最后一天，当月天数  例如31 30
                        BigDecimal balance = remainder.subtract(payFeeAmount.multiply(m)); //剩余费用
                        //计算出剩余钱 是多少天的
                        int day = (int)Math.floor(balance.divide(payFeeAmount.divide(new BigDecimal(lastDay), 2, BigDecimal.ROUND_HALF_UP), 2, BigDecimal.ROUND_HALF_UP).doubleValue());
                        if(day==lastDay){ //这里是四舍五入误差问题  例如 每月费用为40 当月31天  缴费39.99 那么day值就是31 那么开始时间就是当月最后一天
                            startDate = toDate(startLastTime);
                        }else{
                            startDate = toDate(startFirstTime.plusDays(day));
                        }
                        LocalDateTime projectEndTime = LocalDateTime.ofInstant( vo.getEndTime().toInstant(), ZoneId.systemDefault()); //收费项截止时间
                        if(startFirstTime.compareTo(projectEndTime)==1){ //说明当期收费结束了
                            vo.setChargeState(Constant.CHARGE_THIS_END);
                        }
                        LambdaQueryWrapper<ChargeReceiveEntity> receiveWrapper = new LambdaQueryWrapper<>();
                        //账单状态为收费中 并且账单应收区间小于等于下一次收费的应收区间 查出数据
//                       receiveWrapper.le(ChargeReceiveEntity::getPeriod,period).eq(ChargeReceiveEntity::getState,0).eq(ChargeReceiveEntity::getStatus,0);
//                       List<ChargeReceiveEntity> receiveEntityList = chargeReceiveService.list(receiveWrapper); //查出数据后保存，最后批量添加账单明细中

                        List<ChargeReceiveEntity> receiveEntityList = receiveVO.stream().filter(f ->  DateUtil.parse(f.getPeriod()).isBeforeOrEquals(DateUtil.parse(period)) ).collect(Collectors.toList());
                        Date finalStartDate = startDate;
                        receiveDetailList = receiveEntityList.stream().map(item -> {
                            ChargeReceiveDetailEntity receiveDetail = new ChargeReceiveDetailEntity();
                            ChargeReceiveEntity receiveEntity = new ChargeReceiveEntity();
                            String id = String.valueOf(definitionCode.nextId(DefinitionCode.CODE_PREFIX_CHARGE_RECEIVE_DETAIL));
                            receiveDetail.setId(id);
                            receiveDetail.setDetailId(detailId);
                            receiveDetail.setReceiveId(item.getId());
                            receiveDetail.setPeriod(item.getPeriod());
                            if(period.equals(item.getPeriod())){ // 判断,如果本次收费账单最后一个月的应收区间   实收费用大于一个月且不为整月
                                //封装 账单明细表
                                receiveDetail.setReceiveOldDate(finalStartDate); //最后一个月的到期时间
                                receiveDetail.setReceiveAmount(item.getReceiveAmount());
                                receiveDetail.setRevAmount(item.getRevAmount().subtract(balance)); //欠款金额减去本次收费账单最后一个月剩余费用
                                receiveDetail.setPaidAmount(item.getPaidAmount().add(balance));//实收金额加上本次收费账单最后一个月剩余费用
                                //封装 账单表
                                receiveEntity.setId(item.getId());
                                receiveEntity.setDebtStartDate(finalStartDate);
                                receiveEntity.setRevAmount(item.getRevAmount().subtract(balance));
                                receiveEntity.setPaidAmount(item.getPaidAmount().add(balance));
                            }else {
                                //封装 账单明细表
                                receiveDetail.setReceiveOldDate(item.getStartDate());
                                receiveDetail.setReceiveAmount(item.getReceiveAmount());
                                receiveDetail.setRevAmount(new BigDecimal(0));
                                receiveDetail.setPaidAmount(item.getReceiveAmount());
                                receiveDetail.setThisAmount(item.getReceiveAmount());
                                //封装 账单表
                                receiveEntity.setId(item.getId());
                                receiveEntity.setStartDate(item.getStartDate());
                                receiveEntity.setRevAmount(new BigDecimal(0));
                                receiveEntity.setPaidAmount(item.getReceiveAmount());
                                receiveEntity.setState(1);
                            }
                            //修改 账单表
                            chargeReceiveService.updateById(receiveEntity);
                            return receiveDetail;
                        }).collect(Collectors.toList());
                    }
                }else{ //实收费用小于账单第一个月的费用
                    ChargeReceiveEntity receiveEntityFirst = receiveVO.get(0);
                    String id = String.valueOf(definitionCode.nextId(DefinitionCode.CODE_PREFIX_CHARGE_RECEIVE_DETAIL));
                    LocalDateTime startDay = LocalDateTime.ofInstant(receiveVO.get(0).getStartDate().toInstant(), ZoneId.systemDefault()); //第一个月开始日期
                    LocalDateTime startLastTime = LocalDateTime.from(startDay.with(TemporalAdjusters.lastDayOfMonth()));
                    int lastDay = startLastTime.getDayOfMonth(); //取出最后一天，当月天数  例如31 30
                    int day = (int)Math.floor(projectPaidAmount.divide(payFeeAmount.divide(new BigDecimal(lastDay), 2, BigDecimal.ROUND_HALF_UP), 2, BigDecimal.ROUND_HALF_UP).doubleValue());
                    if(day==lastDay){ //这里是四舍五入误差问题  例如 每月费用为40 当月31天  缴费39.99 那么day值就是31 那么开始时间就是当月最后一天
                        startDate = toDate(startLastTime);
                    }else{
                        startDate = toDate(startDay.plusDays(day));
                    }
                    vo.setStartTime(startDate);
                    ChargeReceiveDetailEntity receiveDetail = new ChargeReceiveDetailEntity();
                    receiveDetail.setId(id);
                    receiveDetail.setReceiveId(receiveEntityFirst.getId());
                    receiveDetail.setDetailId(detailId);
                    receiveDetail.setPeriod(receiveEntityFirst.getPeriod());
                    receiveDetail.setReceiveOldDate(startDate);
                    receiveDetail.setReceiveAmount(receiveEntityFirst.getReceiveAmount());
                    receiveDetail.setRevAmount(receiveEntityFirst.getRevAmount().subtract(projectPaidAmount));
                    receiveDetail.setPaidAmount(receiveEntityFirst.getPaidAmount().add(projectPaidAmount));
                    receiveDetailList.add(receiveDetail);

                    //修改 账单表
                    ChargeReceiveEntity receiveEntity = new ChargeReceiveEntity();
                    receiveEntity.setId(receiveEntityFirst.getId());
                    receiveEntity.setStartDate(startDate);
                    receiveEntity.setRevAmount(receiveEntityFirst.getRevAmount().subtract(projectPaidAmount));
                    receiveEntity.setPaidAmount(receiveEntityFirst.getPaidAmount().add(projectPaidAmount));
                    chargeReceiveService.updateById(receiveEntity);
                }
            }
            //开始时间减去一天为详情的缴费结束时间
            LocalDateTime startDay = LocalDateTime.ofInstant(startDate.toInstant(), ZoneId.systemDefault()).minusDays(1);
            chargeDetail.setStartTime(startTime);
            chargeDetail.setEndTime(toDate(startDay));
        }else if(chargeMark.equals(Constant.ONCE_FEE)||chargeMark.equals(Constant.OFTEN_FEE)){ //一次性费用费用或常用性费用
            String id = String.valueOf(definitionCode.nextId(DefinitionCode.CODE_PREFIX_CHARGE_RECEIVE_DETAIL));
            String period = DateUtil.format(startTime, formatter);
            ChargeReceiveDetailEntity receiveDetail = new ChargeReceiveDetailEntity();
            receiveDetail.setId(id);
            receiveDetail.setReceiveId(Constant.ONCE_FEE); //一次性费用给字段一个默认值
            receiveDetail.setDetailId(detailId);
            receiveDetail.setPeriod(period);
            receiveDetail.setReceiveOldDate(startTime);
            receiveDetail.setReceiveAmount(projectPaidAmount);
            receiveDetail.setRevAmount(new BigDecimal(0));
            receiveDetail.setPaidAmount(projectPaidAmount);
            receiveDetailList.add(receiveDetail);
            if(chargeMark.equals(Constant.CYCLE_FEE)&&vo.getConfigVO().getCasual()==1){ //为常用性临时收费
                Date startCasualTime = vo.getStartCasualTime();
                Date endCasualTime = vo.getEndCasualTime();
                //临时时间加一天为收费项 下次开始时间
                LocalDateTime startDay = LocalDateTime.ofInstant(endCasualTime.toInstant(), ZoneId.systemDefault()).plusDays(1);
                startDate = toDate(startDay);
                chargeDetail.setStartTime(startCasualTime);
                chargeDetail.setEndTime(endCasualTime);
            }else {
                chargeDetail.setStartTime(startTime);
                chargeDetail.setEndTime(endTime);
                startDate=endTime;
            }
        }else {
            throw new MicroBusinessException(MicroBusinessError.BIS_20010,"暂时不支持该收费类型");
        }

        //收费项目修改
        ChargeProjectEntity chargeProject = new ChargeProjectEntity();
        chargeProject.setId(projectId);
        chargeProject.setStartTime(startDate);
        BigDecimal revAmountSub = revAmount.subtract(projectPaidAmount);
        chargeProject.setRevAmount(revAmountSub);
        chargeProjectDao.updateById(chargeProject);




        //添加
        chargeDetail.setId(detailId);
        chargeDetail.setProjectId(projectId);
        chargeDetail.setPaidAmount(projectPaidAmount);
        chargeDetail.setState(20243001);
        chargeDetail.setBtn(1);
        chargeDetail.setReceiptNumber(vo.getReceiptNumber());
        chargeDetail.setChargeMethod(vo.getChargeMethod());
    }

    @Override
    public ChargeProjectEntity getListById(Map<String, Object> params) {
        return chargeProjectDao.getListById(params);
    }


    @Override
    public void update(ChargeProjectVO vo) {
        ChargeProjectEntity entity = ChargeProjectConvert.INSTANCE.convert(vo);
        updateById(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(List<Long> idList) {
        removeByIds(idList);
    }
    public static void main(String[] args) throws ParseException {
//        Calendar from = Calendar.getInstance();
//        Date startDate = new SimpleDateFormat("yyyy-MM-dd").parse("2023-05-06");
//        Date receive = new SimpleDateFormat("yyyy-MM-dd").parse("2028-03-06");
//        from.setTime(startDate);
//        Calendar to = Calendar.getInstance();
//        to.setTime(receive);
//        int result = to.get(Calendar.MONTH) - from.get(Calendar.MONTH);
//        int month = (to.get(Calendar.YEAR) - from.get(Calendar.YEAR)) * 12;
//        result = result + month;
//        System.out.println("111:::"+result);
//
//        int d1 = from.get(Calendar.DAY_OF_MONTH);
//        Calendar endDate = Calendar.getInstance();
//        endDate.setTime(startDate);
//        endDate.set(Calendar.DAY_OF_MONTH, 1);
//        endDate.add(Calendar.MONTH, 1);
//        endDate.add(Calendar.DAY_OF_MONTH, -1);
//        int d2 = endDate.get(Calendar.DAY_OF_MONTH);
//        System.out.println("最后一天:::"+d2);
//        int day = d2 - d1;
//
//        LocalDateTime startDay = LocalDateTime.of(2023, 05, 06, 0, 0);
//        LocalDateTime Date = LocalDateTime.of(2028, 03, 06, 0, 0);
//        long betweenMonth = ChronoUnit.MONTHS.between(startDay, Date);
//        LocalDateTime last = LocalDateTime.from(startDay.with(TemporalAdjusters.lastDayOfMonth()));
//        Date date = toDate(last);
//        System.out.println("222:::"+Date);
//        System.out.println("333:::"+date);
//
//        // 构造当月第一天的LocalDate对象
//        LocalDateTime last = LocalDateTime.from(startDay.with(TemporalAdjusters.lastDayOfMonth()));
//        int lastDay = last.getDayOfMonth();
//        int currentDay = startDay.getDayOfMonth();
//        int spaceDay= lastDay-currentDay; //月最后一天减去起始时间天数
//        BigDecimal prices = new BigDecimal("1").setScale(2, BigDecimal.ROUND_HALF_UP);
//        if(currentDay>1){
//            BigDecimal d2s = new BigDecimal(lastDay);
//            BigDecimal dayPrice = prices.divide(d2s, 2, BigDecimal.ROUND_HALF_UP);
//            BigDecimal days = new BigDecimal(spaceDay + 1);
//            BigDecimal results = new BigDecimal(result);
//            BigDecimal add = dayPrice.multiply(days).add(prices.multiply(results));
//        }else{
//            BigDecimal results = new BigDecimal(betweenMonth + 1);
//            BigDecimal add = prices.multiply(results);
//        }
//
//        System.out.println("最后一天:::"+lastDay);
//        System.out.println("当前日期:::"+currentDay);

//        LocalDateTime m1 = LocalDateTime.of(2023, 05, 01, 0, 0);
//        LocalDateTime m2 = LocalDateTime.of(2023, 06, 30, 0, 0);
//        long m3 = ChronoUnit.MONTHS.between(m1, m2);
//        System.out.println("相差月份：：："+m3);
//        LocalDateTime dateTime = LocalDateTime.now();
//
//        // 从 LocalDateTime 对象中提取 YearMonth 对象
//        YearMonth yearMonth = YearMonth.from(dateTime);
//
//        // 输出结果
//        System.out.println("年份：" + yearMonth.getYear());
//        System.out.println("月份：" + yearMonth.getMonthValue());
//        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM"); // 定义格式化模式为"yyyy-MM"
//        String formattedDate = dateTime.format(formatter);
//        System.out.println("年份：" + formattedDate);


//        Date startDate = new SimpleDateFormat("yyyy-MM").parse("2023-05");
//        LocalDateTime startDay = LocalDateTime.ofInstant(startDate.toInstant(), ZoneId.systemDefault());
//        LocalDateTime first = LocalDateTime.from(startDay.with(TemporalAdjusters.firstDayOfMonth()));
//        Date from = Date.from(first.atZone(ZoneId.systemDefault()).toInstant());
//        System.out.println(new SimpleDateFormat("yyyy-MM-dd").format(from));
//       取余运算 和之前方法对比取余
        BigDecimal a = new BigDecimal(0).divideAndRemainder(new BigDecimal(310.48))[1].setScale(2, BigDecimal.ROUND_HALF_UP); //数组下标0 是商值  下标为1是取余的值
        BigDecimal b = new BigDecimal(0).divideAndRemainder(new BigDecimal(310.48))[0].setScale(2, BigDecimal.ROUND_HALF_UP);
//        BigDecimal b = new BigDecimal(310.48).divideAndRemainder(new BigDecimal(189.52))[0];
        System.out.println(a.longValue()+1);
        System.out.println(b);
//        BigDecimal divide = new BigDecimal(310.48).divide(new BigDecimal(310.48).divide(new BigDecimal(31), 2, BigDecimal.ROUND_HALF_UP), 2, BigDecimal.ROUND_HALF_UP);
        System.out.println(a.compareTo(BigDecimal.ZERO) == 0);
    }
    public static Date toDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

}
